{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Go 常见类型的底层原理。\n",
    "- 包括：字符串、切片、map。\n",
    "- 以及：接口、结构体。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.1 什么变量的大小是0字节？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基本类型的字节数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `int` 大小 跟随 系统字长。\n",
    "- 指针的大小 也是 系统字长。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "4\n",
      "8\n",
      "8\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "import \"unsafe\"\n",
    "import \"fmt\"\n",
    "\n",
    "func main() {\n",
    "\tfmt.Println(unsafe.Sizeof(int(0))) // 8 bytes\n",
    "\tfmt.Println(unsafe.Sizeof(int32(0)))\n",
    "\tfmt.Println(unsafe.Sizeof(int64(0)))\n",
    "\tfmt.Println(unsafe.Sizeof(uint(0)))\n",
    "\n",
    "\ti := int(0)\n",
    "\tp := &i\n",
    "\tfmt.Println(unsafe.Sizeof(p))\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空结构体"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 空结构体的地址均相同（在不被包含于其他结构体中的情况下）。\n",
    "- 空结构体主要是为了节约内存: `map`, `channel`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "a: 0x580000\n",
      "b: 0xc0000a0040\n",
      "c: 0x580000\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "type K struct {\n",
    "}\n",
    "\n",
    "func main () {\n",
    "\ta := K{}\n",
    "\tb := int(0)\n",
    "\tc := K{}\n",
    "\n",
    "\tfmt.Println(unsafe.Sizeof(a))\n",
    "\tfmt.Printf(\"a: %p\\n\", &a) // zerobase\n",
    "\tfmt.Printf(\"b: %p\\n\", &b)\n",
    "\tfmt.Printf(\"c: %p\\n\", &c)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/runtime/malloc.go\n",
    "\n",
    "```go\n",
    "// base address for all 0-byte allocations\n",
    "var zerobase uintptr\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a.num1: 0xc0000a000c\n",
      "B: 0x580000\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "type K struct {\n",
    "}\n",
    "\n",
    "type F struct {\n",
    "\tnum1 K\n",
    "\tnum2 int32\n",
    "}\n",
    "\n",
    "func main () {\n",
    "\ta := F{}\n",
    "\tb := K{}\n",
    "\n",
    "\tfmt.Printf(\"a.num1: %p\\n\", &a.num1)\n",
    "\tfmt.Printf(\"B: %p\\n\", &b)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "func main () {\n",
    "\tm := map[string]struct{}{} // hashset: 只有键没有值\n",
    "\tm[\"a\"] = struct{}{}\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Goroutine is running...\n",
      "Main function received the signal.\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "func main() {\n",
    "\t// 使用空结构体创建一个信号通道\n",
    "\tsignal := make(chan struct{})\n",
    "\n",
    "\t// 启动一个 goroutine\n",
    "\tgo func() {\n",
    "\t\tfmt.Println(\"Goroutine is running...\")\n",
    "\t\t// 向通道发送一个空结构体，作为信号\n",
    "\t\tsignal <- struct{}{}\n",
    "\t}()\n",
    "\n",
    "\t// 等待信号\n",
    "\t<-signal\n",
    "\tfmt.Println(\"Main function received the signal.\")\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.2 数组，字符串，切片底层是一样的吗？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字符串的底层: https://go.dev/src/runtime/string.go\n",
    "\n",
    "```go\n",
    "type stringStruct struct { // 结构体名称小写, 代表私有\n",
    "\tstr unsafe.Pointer\n",
    "\tlen int\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/reflect/value.go\n",
    "\n",
    "```go\n",
    "// StringHeader is the runtime representation of a string.\n",
    "// It cannot be used safely or portably and its representation may\n",
    "// change in a later release.\n",
    "// Moreover, the Data field is not sufficient to guarantee the data\n",
    "// it references will not be garbage collected, so programs must keep\n",
    "// a separate, correctly typed pointer to the underlying data.\n",
    "//\n",
    "// Deprecated: Use unsafe.String or unsafe.StringData instead.\n",
    "type StringHeader struct {\n",
    "\tData uintptr\n",
    "\tLen  int\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字符串本质是一个结构体。\n",
    "- `Data` 指针 指向底层的 `Byte` 数组。\n",
    "- `len`表示Byte数组的长度, 还是字符个数? 是Byte数组的长度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unicode / UTF8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n",
      "16\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "import \"unsafe\"\n",
    "\n",
    "func main () {\n",
    "\tfmt.Println(unsafe.Sizeof(\"你好\"))\n",
    "\tfmt.Println(unsafe.Sizeof(\"hello world\"))\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串的访问"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "func main () {\n",
    "\ts := \"你好\"; // UTF8编码, 至少3个字节对应1个字符\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "228\n",
      "189\n",
      "160\n",
      "229\n",
      "165\n",
      "189\n",
      "110\n",
      "105\n",
      "104\n",
      "97\n",
      "111\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "func main () {\n",
    "\ts := \"你好nihao\"; // UTF8编码, 至少3个字节对应1个字符\n",
    "\tfor i := 0; i < len(s); i ++ {\n",
    "\t\tfmt.Println(s[i])\n",
    "\t}\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你\n",
      "好\n",
      "n\n",
      "i\n",
      "h\n",
      "a\n",
      "o\n"
     ]
    }
   ],
   "source": [
    "// https://go.dev/src/runtime/utf8.go  decoderune, encoderune\n",
    "\n",
    "import \"fmt\"\n",
    "\n",
    "func main () {\n",
    "\ts := \"你好nihao\"; // UTF8编码, 至少3个字节对应1个字符\n",
    "\tfor _, chr := range s {\n",
    "\t\t// fmt.Println(chr)\n",
    "\t\tfmt.Printf(\"%c\\n\", chr)\n",
    "\t}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串的切分"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 转为`rune`数组, 切分, 转为`string`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "func main () {\n",
    "\ts := \"你好\"; // UTF8编码, 至少3个字节对应1个字符\n",
    "\tfmt.Println(string([]rune(s)[:1]))\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.3 数组，字符串，切片底层是一样的吗？二"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 切片"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/runtime/slice.go\n",
    "\n",
    "```go\n",
    "type slice struct {\n",
    "\tarray unsafe.Pointer\n",
    "\tlen   int\n",
    "\tcap   int\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "切片的本质是对数组的引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    "+--------+       +-------+-------+-------+---+\n",
    "|  Data  | ----> | Elem1 | Elem2 | Elem3 |...|\n",
    "+--------+       +-------+-------+-------+---+\n",
    "     |           <------- Len ------->\n",
    "     |           <----------- Cap ----------->\n",
    "+-----+         \n",
    "| Len |   (长度：当前使用的元素个数)\n",
    "+-----+         \n",
    "| Cap |   (容量：底层数组的最大容量)\n",
    "+-----+\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 切片的创建"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 根据数组创建: `arr[0:3]` 或者 `slice[0:3]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "arr := [10]int {0, 1, 2, 3, 4 ,5, 6, 7, 8, 9}\n",
    "slice := arr[1:4]\n",
    "fmt.Println(slice)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字面量, 编译时插入创建数组的代码: `slice := []int{1, 2, 3}`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "s := []int{1, 2, 3}\n",
    "fmt.Println(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 可以通过`go build -gcflags -S XX.go`查看汇编辅助理解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- make, 运行时创建数组: `slice := make([]int, 10)`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> https://go.dev/src/runtime/slice.go , `makeslice`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 切片的访问"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 下标\n",
    "- `range`遍历元素\n",
    "- `len(slice)`查看切片长度\n",
    "- `cap(slice)`查看数组容量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 切片的追加"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 不扩容时, 只调整`len`(编译器负责)\n",
    "- 扩容时, 编译时转为调用`runtime.growslice()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://go.dev/src/runtime/slice.go, growslice \n",
    "- 如果期望容量大于当前容量的两倍就会使用期望容量\n",
    "- 如果当前切片的长度小于 1024，将容量翻倍\n",
    "- 如果当前切片的长度大于 1024，每次增加 25%\n",
    "- 切片扩容时，并发不安全，注意切片并发要加锁"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">  go1.24.3 没找到1024相关内容, 视频使用go1.16版本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4 5]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "s := []int{1, 2, 3}\n",
    "s = append(s, 4, 5) // 在 Go 中，append 不会直接修改原切片，而是返回一个新的切片。\n",
    "\t\t\t\t\t\t\t\t\t\t// 如果底层数组容量不足，append 会分配新的数组来存储数据。小于1k时, 一般容量翻倍\n",
    "fmt.Println(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "s := []int{1, 2, 3}\n",
    "_ = append(s, 4, 5) // 想忽略返回值（虽然一般不推荐），可以使用 _ 接收返回值：\n",
    "fmt.Println(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.4 map：重写Redis能用它吗？一"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## HashMap的基本方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 开放寻址法: 在哈希表中发生冲突时，通过一定的探查策略寻找下一个可用位置存储数据。它的核心思想是：所有元素都存储在同一个数组中，如果发生冲突，就“继续找一个空位置”。\n",
    "- 拉链法: 通过将哈希表中的每个槽位扩展为一个链表来解决冲突问题。其核心思想是：在同一个哈希位置存储多个元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Go的map"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/runtime/map_noswiss.go\n",
    "- https://go.dev/blog/swisstable\n",
    "\n",
    "```go\n",
    "// A header for a Go map.\n",
    "type hmap struct {\n",
    "\t// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.\n",
    "\t// Make sure this stays in sync with the compiler's definition.\n",
    "\tcount     int // # live cells == size of map.  Must be first (used by len() builtin)\n",
    "\tflags     uint8\n",
    "\tB         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)\n",
    "\tnoverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details\n",
    "\thash0     uint32 // hash seed\n",
    "\n",
    "\tbuckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.\n",
    "\toldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing\n",
    "\tnevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)\n",
    "\tclearSeq   uint64\n",
    "\n",
    "\textra *mapextra // optional fields\n",
    "}\n",
    "```\n",
    "\n",
    "- `buckets`指向`bmap`\n",
    "```go\n",
    "// A bucket for a Go map.\n",
    "type bmap struct {\n",
    "\t// tophash generally contains the top byte of the hash value\n",
    "\t// for each key in this bucket. If tophash[0] < minTopHash,\n",
    "\t// tophash[0] is a bucket evacuation state instead.\n",
    "\ttophash [abi.OldMapBucketCount]uint8\n",
    "\t// Followed by bucketCnt keys and then bucketCnt elems.\n",
    "\t// NOTE: packing all the keys together and then all the elems together makes the\n",
    "\t// code a bit more complicated than alternating key/elem/key/elem/... but it allows\n",
    "\t// us to eliminate padding which would be needed for, e.g., map[int64]int8.\n",
    "\t// Followed by an overflow pointer.\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.5 map：重写Redis能用它吗？二 *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map的初始化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `make`: "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```go\n",
    "// mapextra holds fields that are not present on all maps.\n",
    "type mapextra struct {\n",
    "\t// If both key and elem do not contain pointers and are inline, then we mark bucket\n",
    "\t// type as containing no pointers. This avoids scanning such maps.\n",
    "\t// However, bmap.overflow is a pointer. In order to keep overflow buckets\n",
    "\t// alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow.\n",
    "\t// overflow and oldoverflow are only used if key and elem do not contain pointers.\n",
    "\t// overflow contains overflow buckets for hmap.buckets.\n",
    "\t// oldoverflow contains overflow buckets for hmap.oldbuckets.\n",
    "\t// The indirection allows to store a pointer to the slice in hiter.\n",
    "\toverflow    *[]*bmap\n",
    "\toldoverflow *[]*bmap\n",
    "\n",
    "\t// nextOverflow holds a pointer to a free overflow bucket.\n",
    "\tnextOverflow *bmap\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%\n",
    "m := make(map[string]int, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字面量: 元素少于25个时, 转为简单赋值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "map[1:2 3:4 5:5]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "hash := map[string]int {\n",
    "\t\"1\" : 2,\n",
    "\t\"3\" : 4,\n",
    "\t\"5\" : 5,\n",
    "}\n",
    "\n",
    "fmt.Println(hash)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "map[1:2 2:4 3:6]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "hash := make(map[string]int, 3)\n",
    "hash[\"1\"] = 2\n",
    "hash[\"2\"] = 4\n",
    "hash[\"3\"] = 6\n",
    "\n",
    "fmt.Println(hash)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字面量: 元素多于25个时, 转为循环赋值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "map[1:1 10:10 11:11 12:12 13:13 14:14 15:15 16:16 17:17 18:18 19:19 2:2 20:20 21:21 22:22 23:23 24:24 25:25 26:26 3:3 4:4 5:5 6:6 7:7 8:8 9:9]\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "hash := make(map[string]int, 26)\n",
    "vstatk := []string{\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\"}\n",
    "vstacv := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}\n",
    "\n",
    "for i := 0; i < len(vstatk); i++ {\n",
    "\thash[vstatk[i]] = vstacv[i]\n",
    "}\n",
    "\n",
    "fmt.Println(hash)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 计算通号"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 匹配"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 写入"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.6 map为什么需要扩容？*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 哈希碰撞"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map的扩容"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- map溢出捅太多时会导致严重的性能下降"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `runtime.mappassign()`可能会触发扩容的情况: \n",
    "  - 装载因子超过6.5(平均每个槽6.5个key)\n",
    "  - 使用了太多的溢出桶(溢出桶超过了普通通)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```go\n",
    "\t// Did not find mapping for key. Allocate new cell & add entry.\n",
    "\n",
    "\t// If we hit the max load factor or we have too many overflow buckets,\n",
    "\t// and we're not already in the middle of growing, start growing.\n",
    "\tif !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {\n",
    "\t\thashGrow(t, h)\n",
    "\t\tgoto again // Growing the table invalidates everything, so try again\n",
    "\t}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map的扩容的类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 等量扩容: 数据不太多但是溢出桶太多了"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 翻倍扩容: 数据太多了, 增加槽/普通桶"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map扩容: 步骤1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 创建一组新桶\n",
    "- `oldbuckets` 指向原有的桶数组\n",
    "- `buckets` 指向新的桶数组\n",
    "- map标记为扩容状态"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map扩容: 步骤2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 将所有的数据从旧桶迁移到新桶\n",
    "- 采用渐进式迁移\n",
    "- 每次操作一个旧桶时，将旧桶数据迁移到新桶\n",
    "- 读取时不进行迁移，只判断读取新桶还是旧桶"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map扩容: 步骤3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 所有的旧桶迁移完成后\n",
    "- `oldbuckets`回收"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.7 怎么解决map的并发问题？一 *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "fatal error: concurrent map read and map write\n",
      "\n",
      "goroutine 18 [running]:\n",
      "internal/runtime/maps.fatal({0x4c5c93?, 0x0?})\n",
      "\t/usr/local/go/src/runtime/panic.go:1058 +0x18\n",
      "main.main.func1()\n",
      "\t \u001b[7m[[ Cell [1] Line 7 ]]\u001b[0m /tmp/gonb_353d02cb/main.go:15 +0x28\n",
      "created by main.main in goroutine 1\n",
      "\t \u001b[7m[[ Cell [1] Line 5 ]]\u001b[0m /tmp/gonb_353d02cb/main.go:13 +0x97\n",
      "\n",
      "goroutine 1 [select (no cases)]:\n",
      "main.main()\n",
      "\t \u001b[7m[[ Cell [1] Line 17 ]]\u001b[0m /tmp/gonb_353d02cb/main.go:25 +0xcb\n",
      "\n",
      "goroutine 19 [runnable]:\n",
      "main.main.func2()\n",
      "\t \u001b[7m[[ Cell [1] Line 13 ]]\u001b[0m /tmp/gonb_353d02cb/main.go:21 +0x28\n",
      "created by main.main in goroutine 1\n",
      "\t \u001b[7m[[ Cell [1] Line 11 ]]\u001b[0m /tmp/gonb_353d02cb/main.go:19 +0xc6\n",
      "exit status 2\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "m := make(map[int]int)\n",
    "\n",
    "go func ()  {\n",
    "\tfor {\n",
    "\t\t_ = m[1]\n",
    "\t}\n",
    "} ()\n",
    "\n",
    "go func ()  {\n",
    "\tfor {\n",
    "\t\tm[2] = 2\n",
    "\t}\n",
    "} ()\n",
    "\n",
    "select {} // 用于阻塞, for{}占用CPU"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map的并发问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `map`的读写有并发问题\n",
    "- A 协程在桶中读数据时，B 协程驱逐了这个桶\n",
    "- A 协程会读到错误的数据或者找不到数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## map并发问题解决方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 给map加锁(mutex)\n",
    "- 使用`sync.Map`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/sync/map.go\n",
    "\n",
    "```go\n",
    "// [the Go memory model]: https://go.dev/ref/mem\n",
    "type Map struct {\n",
    "\t_ noCopy\n",
    "\n",
    "\tmu Mutex\n",
    "\n",
    "\t// read contains the portion of the map's contents that are safe for\n",
    "\t// concurrent access (with or without mu held).\n",
    "\t//\n",
    "\t// The read field itself is always safe to load, but must only be stored with\n",
    "\t// mu held.\n",
    "\t//\n",
    "\t// Entries stored in read may be updated concurrently without mu, but updating\n",
    "\t// a previously-expunged entry requires that the entry be copied to the dirty\n",
    "\t// map and unexpunged with mu held.\n",
    "\tread atomic.Pointer[readOnly]\n",
    "\n",
    "\t// dirty contains the portion of the map's contents that require mu to be\n",
    "\t// held. To ensure that the dirty map can be promoted to the read map quickly,\n",
    "\t// it also includes all of the non-expunged entries in the read map.\n",
    "\t//\n",
    "\t// Expunged entries are not stored in the dirty map. An expunged entry in the\n",
    "\t// clean map must be unexpunged and added to the dirty map before a new value\n",
    "\t// can be stored to it.\n",
    "\t//\n",
    "\t// If the dirty map is nil, the next write to the map will initialize it by\n",
    "\t// making a shallow copy of the clean map, omitting stale entries.\n",
    "\tdirty map[any]*entry\n",
    "\n",
    "\t// misses counts the number of loads since the read map was last updated that\n",
    "\t// needed to lock mu to determine whether the key was present.\n",
    "\t//\n",
    "\t// Once enough misses have occurred to cover the cost of copying the dirty\n",
    "\t// map, the dirty map will be promoted to the read map (in the unamended\n",
    "\t// state) and the next store to the map will make a new dirty copy.\n",
    "\tmisses int\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## sync.Map正常读写"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.8 怎么解决map的并发问题？二 *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## sync.Map追加"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## sync.Map追加后的读写"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## sync.Map删除"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## sync.Map删除后提升dirty"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.9 接口 隐式更好还是显式更好？一"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Go隐式接口特点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 只要实现了接口的全部方法，就是自动实现接口\n",
    "- 可以在不修改代码的情况下抽象出新的接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "F-150\n"
     ]
    }
   ],
   "source": [
    "type Car interface {\n",
    "\tDrive()\n",
    "}\n",
    "\n",
    "type Truck struct {\n",
    "\tModel string\n",
    "}\n",
    "\n",
    "func (t Truck) Drive() {\n",
    "\tfmt.Println(t.Model)\n",
    "}\n",
    "\n",
    "func main () {\n",
    "\tt := Truck{Model: \"F-150\"}\n",
    "\tt.Drive()\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/runtime/iface.go"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 接口值的底层表示"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 接口数据使用 `runtime.iface` 表示\n",
    "- `iface`记录了数据的地址\n",
    "- `iface` 中也记录了接口类型信息和实现的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">  go1.24.3 没找到`type iface struct`相关内容, 视频使用go1.16版本"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类型断言"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 类型断言是一个使用在接口值上的操作\n",
    "- 可以将接口值转换为其他类型值（实现或者兼容接口）\n",
    "- 可以配合 `switch` 进行类型判断"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       ".gonb-err-location {\n",
       "\tbackground: var(--jp-err-color2);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-location:hover {\n",
       "\tborder-width: 2px;\n",
       "\tborder-style: solid;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-context {\n",
       "\tdisplay: none;\n",
       "}\n",
       ".gonb-err-location:hover + .gonb-err-context {\n",
       "\tbackground: var(--jp-dialog-background);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: solid;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tdisplay: block;\n",
       "\twhite-space: pre;\n",
       "\tfont-family: monospace;\n",
       "}\n",
       ".gonb-err-line {\n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\t\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tbackground-color: var(--jp-rendermime-err-background);\n",
       "\tfont-weight: bold;\n",
       "}\n",
       ".gonb-cell-line-info {\n",
       "\tbackground: var(--jp-layout-color2);\n",
       "\tcolor: #999;\n",
       "\tmargin: 0.1em;\n",
       "\tborder: 1px solid var(--jp-border-color1);\n",
       "\tpadding-left: 0.2em;\n",
       "\tpadding-right: 0.2em;\n",
       "}\n",
       "</style>\n",
       "<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-OutputArea-child\">\n",
       "<div class=\"lm-Widget p-Widget jp-RenderedText jp-mod-trusted jp-OutputArea-output\" data-mime-type=\"application/vnd.jupyter.stderr\" style=\"font-family: monospace;\">\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> # gonb_9b1096a3</span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-err-location\">./main.go:17:9: </span> invalid receiver type Car (pointer or interface type)\n",
       "<div class=\"gonb-err-context\">\n",
       "\tModel string\n",
       "}\n",
       "\n",
       "<div class=\"gonb-err-line\">func (c Car) Drive() {\n",
       "</div>\tfmt.Println(c.Model)\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-err-location\">./main.go:18:16: </span> c.Model undefined (type Car has no field or method Model)\n",
       "<div class=\"gonb-err-context\">\n",
       "}\n",
       "\n",
       "func (c Car) Drive() {\n",
       "<div class=\"gonb-err-line\">\tfmt.Println(c.Model)\n",
       "</div>}\n",
       "\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> </span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "ERROR",
     "evalue": "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_9b1096a3/gonb_9b1096a3\": exit status 1",
     "output_type": "error",
     "traceback": [
      "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_9b1096a3/gonb_9b1096a3\": exit status 1"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/d5Knd5bPK\n",
    "\n",
    "type Car interface {\n",
    "\tDrive()\n",
    "}\n",
    "\n",
    "type Truck struct {\n",
    "\tModel string\n",
    "}\n",
    "\n",
    "func (t Truck) Drive() {\n",
    "\tfmt.Println(t.Model)\n",
    "}\n",
    "\n",
    "type Tank struct {\n",
    "\tModel string\n",
    "}\n",
    "\n",
    "func (t Tank) Drive() {\n",
    "\tfmt.Println(t.Model)\n",
    "}\n",
    "\n",
    "func main () {\n",
    "\tvar c Car = Truck{Model: \"F-150\"}\n",
    "\tt := c.(Tank)\n",
    "\tfmt.Println(t)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Successfully asserted to Truck: {F-150}\n",
      "It's a Truck: F-150\n",
      "Successfully asserted to Tank: {M1A2}\n"
     ]
    }
   ],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "type Car interface {\n",
    "    Drive()\n",
    "}\n",
    "\n",
    "type Truck struct {\n",
    "    Model string\n",
    "}\n",
    "\n",
    "func (t Truck) Drive() {\n",
    "    fmt.Println(t.Model)\n",
    "}\n",
    "\n",
    "type Tank struct {\n",
    "    Model string\n",
    "}\n",
    "\n",
    "func (t Tank) Drive() {\n",
    "    fmt.Println(t.Model)\n",
    "}\n",
    "\n",
    "func main() {\n",
    "    // 错误示例：这会在运行时 panic\n",
    "    // var c Car = Truck{Model: \"F-150\"}\n",
    "    // t := c.(Tank) // panic: interface conversion: main.Car is main.Truck, not main.Tank\n",
    "    \n",
    "    // 正确的类型断言方式：\n",
    "    \n",
    "    // 1. 断言为正确的类型\n",
    "    var c Car = Truck{Model: \"F-150\"}\n",
    "    if truck, ok := c.(Truck); ok {\n",
    "        fmt.Println(\"Successfully asserted to Truck:\", truck)\n",
    "    }\n",
    "    \n",
    "    // 2. 使用类型开关\n",
    "    switch v := c.(type) {\n",
    "    case Truck:\n",
    "        fmt.Println(\"It's a Truck:\", v.Model)\n",
    "    case Tank:\n",
    "        fmt.Println(\"It's a Tank:\", v.Model)\n",
    "    default:\n",
    "        fmt.Println(\"Unknown type\")\n",
    "    }\n",
    "    \n",
    "    // 3. 如果要使用 Tank，需要创建 Tank 实例\n",
    "    var c2 Car = Tank{Model: \"M1A2\"}\n",
    "    if tank, ok := c2.(Tank); ok {\n",
    "        fmt.Println(\"Successfully asserted to Tank:\", tank)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.10 接口隐式更好还是显式更好？二"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体和指针实现接口"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| | 结构体实现接口 | 结构体指针实现接口 |\n",
    "|---|---|---|\n",
    "| 结构体初始化变量 | 通过 | 不通过 |\n",
    "| 结构体指针初始化变量 | 通过 | 通过 |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import \"fmt\"\n",
    "\n",
    "// 定义一个接口\n",
    "type Speaker interface {\n",
    "\tSpeak() string\n",
    "}\n",
    "\n",
    "type Person struct {\n",
    "\tName string\n",
    "}\n",
    "\n",
    "// Person 结构体实现接口（值接收者）\n",
    "func (p Person) Speak() string {\n",
    "\treturn \"Person \" + p.Name + \" is speaking\"\n",
    "}\n",
    "\n",
    "type Animal struct {\n",
    "\tName string\n",
    "}\n",
    "\n",
    "// Animal 结构体指针实现接口（指针接收者）\n",
    "func (a *Animal) Speak() string {\n",
    "\treturn \"Animal \" + a.Name + \" is speaking\"\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== 结构体实现接口的情况 ===\n",
      "结构体变量调用接口: Person Alice is speaking\n",
      "结构体指针变量调用接口: Person Bob is speaking\n"
     ]
    }
   ],
   "source": [
    "%% \n",
    "fmt.Println(\"=== 结构体实现接口的情况 ===\")\n",
    "\n",
    "// 结构体初始化变量\n",
    "person := Person{Name: \"Alice\"}\n",
    "var speaker1 Speaker = person // 通过 ✓\n",
    "fmt.Println(\"结构体变量调用接口:\", speaker1.Speak())\n",
    "\t\n",
    "// 结构体指针初始化变量\n",
    "personPtr := &Person{Name: \"Bob\"}\n",
    "var speaker2 Speaker = personPtr // 通过 ✓（Go会自动解引用）\n",
    "fmt.Println(\"结构体指针变量调用接口:\", speaker2.Speak())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       ".gonb-err-location {\n",
       "\tbackground: var(--jp-err-color2);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-location:hover {\n",
       "\tborder-width: 2px;\n",
       "\tborder-style: solid;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-context {\n",
       "\tdisplay: none;\n",
       "}\n",
       ".gonb-err-location:hover + .gonb-err-context {\n",
       "\tbackground: var(--jp-dialog-background);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: solid;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tdisplay: block;\n",
       "\twhite-space: pre;\n",
       "\tfont-family: monospace;\n",
       "}\n",
       ".gonb-err-line {\n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\t\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tbackground-color: var(--jp-rendermime-err-background);\n",
       "\tfont-weight: bold;\n",
       "}\n",
       ".gonb-cell-line-info {\n",
       "\tbackground: var(--jp-layout-color2);\n",
       "\tcolor: #999;\n",
       "\tmargin: 0.1em;\n",
       "\tborder: 1px solid var(--jp-border-color1);\n",
       "\tpadding-left: 0.2em;\n",
       "\tpadding-right: 0.2em;\n",
       "}\n",
       "</style>\n",
       "<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-OutputArea-child\">\n",
       "<div class=\"lm-Widget p-Widget jp-RenderedText jp-mod-trusted jp-OutputArea-output\" data-mime-type=\"application/vnd.jupyter.stderr\" style=\"font-family: monospace;\">\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> # gonb_ff042f14</span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[5]: Line 5</span>\n",
       "<span class=\"gonb-err-location\">./main.go:51:5: </span> declared and not used: speaker3\n",
       "<div class=\"gonb-err-context\">\n",
       "fmt.Println(&#34;\\n=== 结构体指针实现接口的情况 ===&#34;)\n",
       "// 结构体初始化变量\n",
       "animal := Animal{Name: &#34;Cat&#34;}\n",
       "<div class=\"gonb-err-line\">var speaker3 Speaker = animal // 不通过 ✗ - 编译错误\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[5]: Line 5</span>\n",
       "<span class=\"gonb-err-location\">./main.go:51:24: </span> cannot use animal (variable of struct type Animal) as Speaker value in variable declaration: Animal does not implement Speaker (method Speak has pointer receiver)\n",
       "<div class=\"gonb-err-context\">\n",
       "fmt.Println(&#34;\\n=== 结构体指针实现接口的情况 ===&#34;)\n",
       "// 结构体初始化变量\n",
       "animal := Animal{Name: &#34;Cat&#34;}\n",
       "<div class=\"gonb-err-line\">var speaker3 Speaker = animal // 不通过 ✗ - 编译错误\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> </span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "ERROR",
     "evalue": "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_ff042f14/gonb_ff042f14\": exit status 1",
     "output_type": "error",
     "traceback": [
      "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_ff042f14/gonb_ff042f14\": exit status 1"
     ]
    }
   ],
   "source": [
    "%% \n",
    "fmt.Println(\"\\n=== 结构体指针实现接口的情况 ===\")\n",
    "// 结构体初始化变量\n",
    "animal := Animal{Name: \"Cat\"}\n",
    "var speaker3 Speaker = animal // 不通过 ✗ - 编译错误"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== 结构体指针实现接口的情况 ===\n",
      "结构体变量(取地址后)调用接口: Animal Cat is speaking\n"
     ]
    }
   ],
   "source": [
    "%% \n",
    "fmt.Println(\"\\n=== 结构体指针实现接口的情况 ===\")\n",
    "// 结构体初始化变量\n",
    "animal := Animal{Name: \"Cat\"}\n",
    "var speaker3 Speaker = &animal\n",
    "fmt.Println(\"结构体变量(取地址后)调用接口:\", speaker3.Speak())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== 结构体指针实现接口的情况 ===\n",
      "结构体指针变量调用接口: Animal Dog is speaking\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "fmt.Println(\"\\n=== 结构体指针实现接口的情况 ===\")\n",
    "// 结构体指针初始化变量\n",
    "animalPtr := &Animal{Name: \"Dog\"}\n",
    "var speaker4 Speaker = animalPtr // 通过 ✓\n",
    "fmt.Println(\"结构体指针变量调用接口:\", speaker4.Speak())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       ".gonb-err-location {\n",
       "\tbackground: var(--jp-err-color2);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-location:hover {\n",
       "\tborder-width: 2px;\n",
       "\tborder-style: solid;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-context {\n",
       "\tdisplay: none;\n",
       "}\n",
       ".gonb-err-location:hover + .gonb-err-context {\n",
       "\tbackground: var(--jp-dialog-background);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: solid;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tdisplay: block;\n",
       "\twhite-space: pre;\n",
       "\tfont-family: monospace;\n",
       "}\n",
       ".gonb-err-line {\n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\t\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tbackground-color: var(--jp-rendermime-err-background);\n",
       "\tfont-weight: bold;\n",
       "}\n",
       ".gonb-cell-line-info {\n",
       "\tbackground: var(--jp-layout-color2);\n",
       "\tcolor: #999;\n",
       "\tmargin: 0.1em;\n",
       "\tborder: 1px solid var(--jp-border-color1);\n",
       "\tpadding-left: 0.2em;\n",
       "\tpadding-right: 0.2em;\n",
       "}\n",
       "</style>\n",
       "<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-OutputArea-child\">\n",
       "<div class=\"lm-Widget p-Widget jp-RenderedText jp-mod-trusted jp-OutputArea-output\" data-mime-type=\"application/vnd.jupyter.stderr\" style=\"font-family: monospace;\">\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> # gonb_88047c52</span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[4]: Line 6</span>\n",
       "<span class=\"gonb-err-location\">./main.go:35:5: </span> declared and not used: errorSpeaker\n",
       "<div class=\"gonb-err-context\">\n",
       "fmt.Println(&#34;\\n=== 演示编译错误的情况 ===&#34;)\n",
       "// 下面这行会导致编译错误，因为Animal结构体没有实现Speaker接口\n",
       "// 只有*Animal指针类型实现了Speaker接口\n",
       "<div class=\"gonb-err-line\">var errorSpeaker Speaker = Animal{Name: &#34;ErrorAnimal&#34;}\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[4]: Line 6</span>\n",
       "<span class=\"gonb-err-location\">./main.go:35:28: </span> cannot use Animal{…} (value of struct type Animal) as Speaker value in variable declaration: Animal does not implement Speaker (method Speak has pointer receiver)\n",
       "<div class=\"gonb-err-context\">\n",
       "fmt.Println(&#34;\\n=== 演示编译错误的情况 ===&#34;)\n",
       "// 下面这行会导致编译错误，因为Animal结构体没有实现Speaker接口\n",
       "// 只有*Animal指针类型实现了Speaker接口\n",
       "<div class=\"gonb-err-line\">var errorSpeaker Speaker = Animal{Name: &#34;ErrorAnimal&#34;}\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> </span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "ERROR",
     "evalue": "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_88047c52/gonb_88047c52\": exit status 1",
     "output_type": "error",
     "traceback": [
      "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_88047c52/gonb_88047c52\": exit status 1"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "fmt.Println(\"\\n=== 演示编译错误的情况 ===\")\n",
    "// 下面这行会导致编译错误，因为Animal结构体没有实现Speaker接口\n",
    "// 只有*Animal指针类型实现了Speaker接口\n",
    "var errorSpeaker Speaker = Animal{Name: \"ErrorAnimal\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "值接收者实现接口（如`Person`）： \n",
    "- 结构体变量可以直接赋值给接口 ✓\n",
    "- 结构体指针变量也可以赋值给接口 ✓（Go自动解引用）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指针接收者实现接口（如`Animal`）：\n",
    "- 结构体变量不能直接赋值给接口 ✗（需要取地址）\n",
    "- 结构体指针变量可以直接赋值给接口 ✓"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Go语言的自动转换规则：\n",
    "- 当方法集包含值接收者时，类型`T`和`*T`都可以调用\n",
    "- 当方法集只包含指针接收者时，只有`*T`可以调用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空接口值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `runtime.eface`结构体\n",
    "- 空接口底层不是普通接口\n",
    "- 空接口值可以承载任何数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空接口的用途"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 作为任意类型的函数入参"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type K interface {\n",
    "}\n",
    "\n",
    "func k(i interface{}) {\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%\n",
    "k(\"test empty interface!\")\n",
    "k(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.11 nil，空接口，空结构体有什么区别"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## nil"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `nil`是空, 并不一定是空指针\n",
    "- `nil`是6中类型的\"零值\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://go.dev/src/builtin/builtin.go\n",
    "\n",
    "```go\n",
    "// nil is a predeclared identifier representing the zero value for a\n",
    "// pointer, channel, func, interface, map, or slice type.\n",
    "var nil Type // Type must be a pointer, channel, func, interface, map, or slice type\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "var a *int\n",
    "fmt.Println(a == nil)\n",
    "\n",
    "var m map[int]int\n",
    "fmt.Println(m == nil)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       ".gonb-err-location {\n",
       "\tbackground: var(--jp-err-color2);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-location:hover {\n",
       "\tborder-width: 2px;\n",
       "\tborder-style: solid;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-context {\n",
       "\tdisplay: none;\n",
       "}\n",
       ".gonb-err-location:hover + .gonb-err-context {\n",
       "\tbackground: var(--jp-dialog-background);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: solid;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tdisplay: block;\n",
       "\twhite-space: pre;\n",
       "\tfont-family: monospace;\n",
       "}\n",
       ".gonb-err-line {\n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\t\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tbackground-color: var(--jp-rendermime-err-background);\n",
       "\tfont-weight: bold;\n",
       "}\n",
       ".gonb-cell-line-info {\n",
       "\tbackground: var(--jp-layout-color2);\n",
       "\tcolor: #999;\n",
       "\tmargin: 0.1em;\n",
       "\tborder: 1px solid var(--jp-border-color1);\n",
       "\tpadding-left: 0.2em;\n",
       "\tpadding-right: 0.2em;\n",
       "}\n",
       "</style>\n",
       "<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-OutputArea-child\">\n",
       "<div class=\"lm-Widget p-Widget jp-RenderedText jp-mod-trusted jp-OutputArea-output\" data-mime-type=\"application/vnd.jupyter.stderr\" style=\"font-family: monospace;\">\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> # gonb_45b7d7a5</span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[9]: Line 6</span>\n",
       "<span class=\"gonb-err-location\">./main.go:15:18: </span> invalid operation: m == a (mismatched types map[int]int and *int)\n",
       "<div class=\"gonb-err-context\">\n",
       "var a *int\n",
       "var m map[int]int\n",
       "\n",
       "<div class=\"gonb-err-line\">fmt.Println(m == a)\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> </span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "ERROR",
     "evalue": "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_45b7d7a5/gonb_45b7d7a5\": exit status 1",
     "output_type": "error",
     "traceback": [
      "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_45b7d7a5/gonb_45b7d7a5\": exit status 1"
     ]
    }
   ],
   "source": [
    "%% \n",
    "\n",
    "var a *int\n",
    "var m map[int]int\n",
    "\n",
    "fmt.Println(m == a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       ".gonb-err-location {\n",
       "\tbackground: var(--jp-err-color2);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-location:hover {\n",
       "\tborder-width: 2px;\n",
       "\tborder-style: solid;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "}\n",
       ".gonb-err-context {\n",
       "\tdisplay: none;\n",
       "}\n",
       ".gonb-err-location:hover + .gonb-err-context {\n",
       "\tbackground: var(--jp-dialog-background);  \n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: solid;\n",
       "\tborder-width: 1px;\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tdisplay: block;\n",
       "\twhite-space: pre;\n",
       "\tfont-family: monospace;\n",
       "}\n",
       ".gonb-err-line {\n",
       "\tborder-radius: 3px;\n",
       "\tborder-style: dotted;\n",
       "\tborder-width: 1px;\t\n",
       "\tborder-color: var(--jp-border-color2);\n",
       "\tbackground-color: var(--jp-rendermime-err-background);\n",
       "\tfont-weight: bold;\n",
       "}\n",
       ".gonb-cell-line-info {\n",
       "\tbackground: var(--jp-layout-color2);\n",
       "\tcolor: #999;\n",
       "\tmargin: 0.1em;\n",
       "\tborder: 1px solid var(--jp-border-color1);\n",
       "\tpadding-left: 0.2em;\n",
       "\tpadding-right: 0.2em;\n",
       "}\n",
       "</style>\n",
       "<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-OutputArea-child\">\n",
       "<div class=\"lm-Widget p-Widget jp-RenderedText jp-mod-trusted jp-OutputArea-output\" data-mime-type=\"application/vnd.jupyter.stderr\" style=\"font-family: monospace;\">\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> # gonb_45b7d7a5</span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "<span class=\"gonb-cell-line-info\">Cell[10]: Line 5</span>\n",
       "<span class=\"gonb-err-location\">./main.go:14:18: </span> invalid operation: c == nil (mismatched types struct{} and untyped nil)\n",
       "<div class=\"gonb-err-context\">\n",
       "\n",
       "var c struct {}\n",
       "\n",
       "<div class=\"gonb-err-line\">fmt.Println(c == nil)\n",
       "</div>\n",
       "}\n",
       "\n",
       "</div>\n",
       "\n",
       "<br/>\n",
       "\n",
       "\n",
       "<span style=\"white-space: pre;\"> </span>\n",
       "\n",
       "<br/>\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "ERROR",
     "evalue": "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_45b7d7a5/gonb_45b7d7a5\": exit status 1",
     "output_type": "error",
     "traceback": [
      "failed to run \"/usr/local/go/bin/go build -o /tmp/gonb_45b7d7a5/gonb_45b7d7a5\": exit status 1"
     ]
    }
   ],
   "source": [
    "%% \n",
    "\n",
    "var c struct {}\n",
    "\n",
    "fmt.Println(c == nil)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空结构体"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 空结构体是Go中非常特殊的类型\n",
    "- 空结构体的值不是`nil`\n",
    "- 空结构体的指针也不是`nil`，但是都相同(zerobase)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空接口"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 空接口不一定是\"nil接口\"\n",
    "- 两个属性都`nil`才是`nil`接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "var a interface{}\n",
    "var b interface{}\n",
    "\n",
    "fmt.Println(a == nil)\n",
    "fmt.Println(b == nil)\n",
    "fmt.Println(a == b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "var a interface{}\n",
    "var c *int\n",
    "\n",
    "fmt.Println(a == nil)\n",
    "fmt.Println(c == nil)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false\n",
      "true\n",
      "nil的类型是: <nil>\n",
      "a的类型是: *int\n",
      "c的类型是: *int\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "var a interface{}\n",
    "var c *int\n",
    "a = c\n",
    "\n",
    "fmt.Println(a == nil)\n",
    "fmt.Println(c == nil)\n",
    "\n",
    "fmt.Printf(\"nil的类型是: %T\\n\", nil)\n",
    "fmt.Printf(\"a的类型是: %T\\n\", a)\n",
    "fmt.Printf(\"c的类型是: %T\\n\", c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.12 实战：内存对齐是如何优化程序效率的？一"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "S1: 8\n",
      "S2: 8\n",
      "S3: 4\n",
      "S4: 12\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type S1 struct {\n",
    "\tnum1 int32\n",
    "\tnum2 int32\n",
    "}\n",
    "\n",
    "type S2 struct {\n",
    "\tnum1 int16\n",
    "\tnum2 int32\n",
    "}\n",
    "\n",
    "type S3 struct {\n",
    "\tnum1 int16\n",
    "\tnum2 int16\n",
    "}\n",
    "\n",
    "type S4 struct {\n",
    "\tnum1 int16\n",
    "\tnum2 int32\n",
    "\tnum3 int16\n",
    "}\n",
    "\n",
    "fmt.Printf(\"S1: %d\\n\", unsafe.Sizeof(S1{}))\n",
    "fmt.Printf(\"S2: %d\\n\", unsafe.Sizeof(S2{}))\n",
    "fmt.Printf(\"S3: %d\\n\", unsafe.Sizeof(S3{}))\n",
    "fmt.Printf(\"S4: %d\\n\", unsafe.Sizeof(S4{}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "S4 size: 12\n",
      "num1 offset: 0, size: 2\n",
      "num2 offset: 4, size: 4\n",
      "num3 offset: 8, size: 2\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type S4 struct {\n",
    "    num1 int16\n",
    "    num2 int32\n",
    "    num3 int16\n",
    "}\n",
    "    \n",
    "s := S4{}\n",
    "    \n",
    "fmt.Printf(\"S4 size: %d\\n\", unsafe.Sizeof(s))\n",
    "fmt.Printf(\"num1 offset: %d, size: %d\\n\", \n",
    "    unsafe.Offsetof(s.num1), unsafe.Sizeof(s.num1))\n",
    "fmt.Printf(\"num2 offset: %d, size: %d\\n\", \n",
    "    unsafe.Offsetof(s.num2), unsafe.Sizeof(s.num2))\n",
    "fmt.Printf(\"num3 offset: %d, size: %d\\n\", \n",
    "    unsafe.Offsetof(s.num3), unsafe.Sizeof(s.num3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "S5 size: 24\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type S5 struct {\n",
    "    num1 int64\n",
    "    num2 int32\n",
    "    num3 int64\n",
    "}\n",
    "    \n",
    "fmt.Printf(\"S5 size: %d\\n\", unsafe.Sizeof(S5{}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 对齐系数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int8 对齐: 1\n",
      "int16 对齐: 2\n",
      "int32 对齐: 4\n",
      "int64 对齐: 8\n",
      "float32 对齐: 4\n",
      "float64 对齐: 8\n",
      "string 对齐: 8, 大小: 16\n",
      "指针对齐: 8\n"
     ]
    }
   ],
   "source": [
    "import (\n",
    "    \"fmt\"\n",
    "    \"unsafe\"\n",
    ")\n",
    "\n",
    "func main() {\n",
    "    // 在64位系统上\n",
    "    fmt.Printf(\"int8 对齐: %d\\n\", unsafe.Alignof(int8(0)))     // 1\n",
    "    fmt.Printf(\"int16 对齐: %d\\n\", unsafe.Alignof(int16(0)))   // 2\n",
    "    fmt.Printf(\"int32 对齐: %d\\n\", unsafe.Alignof(int32(0)))   // 4\n",
    "    fmt.Printf(\"int64 对齐: %d\\n\", unsafe.Alignof(int64(0)))   // 8\n",
    "    fmt.Printf(\"float32 对齐: %d\\n\", unsafe.Alignof(float32(0))) // 4\n",
    "    fmt.Printf(\"float64 对齐: %d\\n\", unsafe.Alignof(float64(0))) // 8\n",
    "    var s string\n",
    "    fmt.Printf(\"string 对齐: %d, 大小: %d\\n\", unsafe.Alignof(s), unsafe.Sizeof(s)) // 8, 16\n",
    "    \n",
    "    // 指针在64位系统上\n",
    "    var p *int\n",
    "    fmt.Printf(\"指针对齐: %d\\n\", unsafe.Alignof(p))  // 8\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.13 实战：内存对齐是如何优化程序效率的？二"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体对齐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 结构体对齐分为内部对齐和结构体之间对齐\n",
    "- 内部对齐：考虑成员大小和成员的对齐系数\n",
    "- 结构体长度填充：考虑自身对齐系数和系统字长"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体内部对齐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 指的是结构体内部成员的相对位置（偏移量）\n",
    "- 每个成员的偏移量是自身大小与其对齐系数较小值的倍数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体长度填充"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 指的是结构体通过增加长度，对齐系统字长\n",
    "- 结构体长度是最大成员长度与系统字长较小的整数倍"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a offset: 0\n",
      "b offset: 8\n",
      "c offset: 24\n",
      "struct size: 32\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type Example struct {\n",
    "    a byte   // 1字节, 对齐系数1\n",
    "    b string // 16字节, 对齐系数8\n",
    "    c int16  // 2字节, 对齐系数2\n",
    "}\n",
    "\n",
    "var e Example\n",
    "\n",
    "fmt.Println(\"a offset:\", unsafe.Offsetof(e.a))\n",
    "fmt.Println(\"b offset:\", unsafe.Offsetof(e.b))\n",
    "fmt.Println(\"c offset:\", unsafe.Offsetof(e.c))\n",
    "fmt.Println(\"struct size:\", unsafe.Sizeof(e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 节约结构体空间"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 可以尝试通过调整成员顺序，节约空间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a offset: 0\n",
      "c offset: 2\n",
      "b offset: 8\n",
      "struct size: 24\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type Example struct {\n",
    "    a byte   // 1字节, 对齐系数1\n",
    "    c int16  // 2字节, 对齐系数2\n",
    "    b string // 16字节, 对齐系数8\n",
    "}\n",
    "\n",
    "var e Example\n",
    "\n",
    "fmt.Println(\"a offset:\", unsafe.Offsetof(e.a))\n",
    "fmt.Println(\"c offset:\", unsafe.Offsetof(e.c))\n",
    "fmt.Println(\"b offset:\", unsafe.Offsetof(e.b))\n",
    "fmt.Println(\"struct size:\", unsafe.Sizeof(e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体对齐系数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 结构体的对齐系数是其成员的最大对齐系数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 空结构体的对齐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 空结构体单独出现时，地址为 zerobase\n",
    "- 空结构体出现在结构体中时，地址跟随前一个变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a offset: 0\n",
      "z offset: 1\n",
      "b offset: 8\n",
      "c offset: 24\n",
      "struct size: 32\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type Example struct {\n",
    "    a byte   // 1字节, 对齐系数1\n",
    "    z struct {}\n",
    "    b string // 16字节, 对齐系数8\n",
    "    c int16  // 2字节, 对齐系数2\n",
    "}\n",
    "\n",
    "var e Example\n",
    "\n",
    "fmt.Println(\"a offset:\", unsafe.Offsetof(e.a))\n",
    "fmt.Println(\"z offset:\", unsafe.Offsetof(e.z))\n",
    "fmt.Println(\"b offset:\", unsafe.Offsetof(e.b))\n",
    "fmt.Println(\"c offset:\", unsafe.Offsetof(e.c))\n",
    "fmt.Println(\"struct size:\", unsafe.Sizeof(e))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a offset: 0\n",
      "c offset: 2\n",
      "b offset: 8\n",
      "z offset: 24\n",
      "struct size: 32\n"
     ]
    }
   ],
   "source": [
    "%%\n",
    "\n",
    "type Example struct {\n",
    "    a byte   // 1字节, 对齐系数1\n",
    "    c int16  // 2字节, 对齐系数2\n",
    "    b string // 16字节, 对齐系数8\n",
    "    z struct {}\n",
    "}\n",
    "\n",
    "var e Example\n",
    "\n",
    "fmt.Println(\"a offset:\", unsafe.Offsetof(e.a))\n",
    "fmt.Println(\"c offset:\", unsafe.Offsetof(e.c))\n",
    "fmt.Println(\"b offset:\", unsafe.Offsetof(e.b))\n",
    "fmt.Println(\"z offset:\", unsafe.Offsetof(e.z))\n",
    "fmt.Println(\"struct size:\", unsafe.Sizeof(e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.14 本章小结"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Go (gonb)",
   "language": "go",
   "name": "gonb"
  },
  "language_info": {
   "codemirror_mode": "",
   "file_extension": ".go",
   "mimetype": "text/x-go",
   "name": "go",
   "nbconvert_exporter": "",
   "pygments_lexer": "",
   "version": "go1.24.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
